package com.spring.context.impl;


import com.spring.aop.Advisor;
import com.spring.aop.AopBeanPostProcessor;
import com.spring.bean.BeanDefinition;
import com.spring.beanpostprocessor.*;
import com.spring.context.BeanDefinitionRegistry;
import com.spring.event.ApplicationEvent;
import com.spring.event.EventListener;
import com.spring.factory.BeanFactory;
import com.spring.factory.impl.AbstractAutowireBeanFactory;
import com.spring.factory.impl.SuperBeanFactory;
import com.spring.transaction.TransactionManager;
import com.spring.util.SpringUtil;
import com.spring.util.StringUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * 抽象的上下文
 * 实现  BeanDefinitionRegistry ,管理所有的 bean 定义
 *
 * 简单定义了 容器的初始化逻辑
 */
@Slf4j
public abstract class AbstractApplicationContext implements BeanFactory, BeanDefinitionRegistry {
	/**
	 * 保存 bean 定义
	 */
	protected ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
	/**
	 * 保存bean 名字
	 */
	private final Set<String> beanNames = new HashSet<>(256);
	
	// 保存所有的代理信息类
	protected ArrayList<Advisor> advisorList = new ArrayList<>();
	
	
	/**
	 * 保存所有 BeanFactoryPostProcessor
	 *
	 * BeanFactoryPostProcessor 主要是用来处理 类定义的，不在普通的bean 声明周期中
	 *
	 * BeanPostProcessor 要给普通的bean 进行处理，所以不在context 中出现，而是在  factory 里面
	 */
	private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();
	
	/**
	 * 持有一个工厂引用,bean 的各种获取委托给 工厂
	 *
	 * bean定义在 自己这里
	 */
	protected AbstractAutowireBeanFactory factory;
	
	
	private final Map<Class<? extends ApplicationEvent>, List<EventListener>> eventMap = new HashMap<>(16);
	
	private final ExecutorService listenerExecutor = Executors.newSingleThreadExecutor();
	
	
	public AbstractApplicationContext() {
		this.factory = new SuperBeanFactory(this);
	}
	
	public ArrayList<Advisor> getAdvisorList() {
		return advisorList;
	}
	
	public void addAdvisor(Advisor advisor) {
		advisorList.add(advisor);
	}
	
	@Override
	public Object getBean(String name) {
		return factory.getBean(name);
	}
	
	@Override
	public <T> T getBean(String name, Class<T> clazz) {
		return factory.getBean(name, clazz);
	}
	
	/**
	 * 容器入口方法，核心方法
	 */
	public void refresh() {
		// 预处理一下 工厂
		log.info("###预处理Bean工厂###");
		prepareBeanFactory(factory);
		
		// 模板方法，可以对这个 factory 对一些操作，比如添加 BeanPostProcessor
		log.info("###Bean工厂准备完成###");
		postProcessBeanFactory(factory);
		
		// 现在开始调用 BeanFactoryPostProcessor 在 bean工厂完成准备之后进一步处理
		// 比如加载更多的bean定义
		log.info("###反复加载更多的Bean定义信息###");
		invokeBeanFactoryPostProcessors(factory);
		
		
		// 注册 BeanPostProcessor  ，这些 特殊bean 会在后面普通bean 的创建过程中生效,所以创建时间早于普通bean
		log.info("###注册创建 BeanPostProcessor为后续流程准备###");
		registerBeanPostProcessors();
		
		
		// 已经全部准备好了，在初始化 普通单例bean 之前，还可以扩展一些操作
		log.info("###所有类定义信息已准备完成###");
		onRefresh(factory);
		
		
		// 注册监听器
		log.info("###注册监听器###");
		registerListeners(factory);
		
		
		// 普通 Bean 的创建
		log.info("###创建常规Bean###");
		finishBeanFactoryInitialization();
		
		log.info("###容器刷新完成###");
	}
	
	
	/**
	 * 准备下一些bean 工厂的准备工作
	 *
	 * 比如：添加一些接口处理器之类
	 */
	private void prepareBeanFactory(AbstractAutowireBeanFactory factory) {
		// 添加ApplicationContextAware接口处理器
		factory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		factory.addBeanPostProcessor(new ValueAnnotationHandler());
		factory.addBeanPostProcessor(new EventPostProcessor(this));
		factory.addBeanPostProcessor(new AopBeanPostProcessor(this));
		
		
		beanFactoryPostProcessors.add(new ConfigurationClassPostProcessor(this));
		beanFactoryPostProcessors.add(new TransactionBeanDefinitionRegistryPostProcessor(this));
		
		// 注册一个事务管理器，无论有没有启用事务
		registryBeanDefinition("transactionManager", TransactionManager.defaultTransactionManagerDefinition());
		
		// 注册一个工具类方便静态获取 bean
		registryBeanDefinition(new BeanDefinition(SpringUtil.class));
	}
	
	/**
	 * 在准备好工厂后提供一个机会让子类可以对工厂做一些处理，比如额外添加一些 BeanPostProcessor
	 */
	protected void postProcessBeanFactory(AbstractAutowireBeanFactory factory) {
		// 暂时什么也不做
	}
	
	
	/**
	 * 在 bean 工厂准备好之后，调用 bean工厂后置处理器
	 *
	 * 在这里，可以进一步加载扫描 bean 定义
	 */
	private void invokeBeanFactoryPostProcessors(AbstractAutowireBeanFactory factory) {
		// 常规 BeanFactoryPostProcessor
		List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
		List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
		List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
		
		HashSet<String> processedBean = new HashSet<>();
		
		// 如果是 BeanDefinitionRegistryPostProcessor  优先调用
		// 常规的 BeanFactoryPostProcessor 保存一下后面再用
		
		// 无论如何  BeanDefinitionRegistryPostProcessor 优先调用一次
		for (BeanFactoryPostProcessor beanFactoryPostProcessor : this.beanFactoryPostProcessors) {
			if (beanFactoryPostProcessor instanceof BeanDefinitionRegistryPostProcessor) {
				BeanDefinitionRegistryPostProcessor processor = (BeanDefinitionRegistryPostProcessor) beanFactoryPostProcessor;
				processor.postProcessBeanDefinitionRegistry(this);
				registryProcessors.add(processor);
			} else {
				regularPostProcessors.add(beanFactoryPostProcessor);
			}
		}
		
		
		// 这段逻辑是因为 注册器 也可能注册 另一个注册器，所以不断查找
		boolean flag = true;
		while (flag) {
			flag = false;
			// 查找所有bean注册器
			List<String> postProcessorNames = this.getAllBeanDefinition()
					.stream().filter(bd -> BeanDefinitionRegistryPostProcessor.class.isAssignableFrom(bd.getBeanClass()))
					.map(BeanDefinition::getBeanName).collect(Collectors.toList());
			
			// 如果还有没有处理过的 注册器，就获取这个注册器并处理
			for (String postProcessorName : postProcessorNames) {
				if (!processedBean.contains(postProcessorName)) {
					flag = true;
					processedBean.add(postProcessorName);
					// 获取这个注册器，并保存起来，等下统一调用
					currentRegistryProcessors.add(factory.getBean(postProcessorName, BeanDefinitionRegistryPostProcessor.class));
				}
			}
		}
		
		// 调用所有的注册器
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, this);
		registryProcessors.addAll(currentRegistryProcessors);
		currentRegistryProcessors.clear();
		
		// 到这里为止，所有类定义全部注册完毕了，接下来准备调用 BeanFactoryProcessor 了
		invokeBeanFactoryPostProcessors(registryProcessors, factory);
		invokeBeanFactoryPostProcessors(regularPostProcessors, factory);
	}
	
	private static void invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor> postProcessors, AbstractAutowireBeanFactory beanFactory) {
		for (BeanFactoryPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessBeanFactory(beanFactory);
		}
	}
	
	// 调用所有的注册器
	private static void invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
		for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessBeanDefinitionRegistry(registry);
		}
	}
	
	
	/**
	 * 在单例bean 初始化之前，给子类一个可以插入部分逻辑的空间，一个空模板方法
	 */
	private void onRefresh(AbstractAutowireBeanFactory factory) {
	}
	
	
	/**
	 * 注册监听器系统
	 */
	private void registerListeners(AbstractAutowireBeanFactory factory) {
		// 为了消息发送者 和 监听器解耦，他们之间没有任何依赖关系
		// 通过容器来接收并转发消息
		
		// 只要实现了EventListener 接口的类都会注册到容器中 ,可以在 BeanPostProcessor 阶段处理下
	}
	
	/**
	 * 结束beanFactory 的初始化
	 *
	 * 这里准备初始化所有普通的 单例bean
	 */
	protected void finishBeanFactoryInitialization() {
		factory.instantSingletons();
	}
	
	
	/**
	 * 实例化 BeanPostProcessor , 并放到 factory 里面保存起来，后续 bean 实例化时用到
	 */
	protected void registerBeanPostProcessors() {
		List<String> allBeanNameByType = getAllBeanNameByType(BeanPostProcessor.class);
		for (String beanName : allBeanNameByType) {
			BeanPostProcessor bean = (BeanPostProcessor) getBean(beanName);
			this.factory.addBeanPostProcessor(bean);
		}
	}
	
	
	/**
	 * 容器销毁方法
	 */
	public void close() {
		// 通知工厂销毁所有bean
		factory.destroySingletons();
	}
	
	
	@Override
	public void registryBeanDefinition(String beanName, BeanDefinition bd) {
		// 注册bean定义时， 检查 beanName 是否重复
		if (containsBeanDefinition(beanName)) {
			log.error("bean名称重复定义: {}", beanName);
			throw new RuntimeException("bean名称重复定义");
		}
		log.info("注册bean定义 {}", beanName);
		
		beanDefinitionMap.put(beanName, bd);
		beanNames.add(beanName);
		
		// 如果有必要，构建切面通知类并保存起来
		Advisor advisor = Advisor.buildAdvisorIfNecessary(bd, this);
		if (advisor != null) {
			this.advisorList.add(advisor);
		}
	}
	
	/**
	 * 快速注册
	 */
	private void registryBeanDefinition(BeanDefinition bd) {
		registryBeanDefinition(bd.getBeanName(), bd);
	}
	
	
	@SuppressWarnings("all")
	public void addListener(Class<? extends ApplicationEvent> event, EventListener listener) {
		List<EventListener> listeners = eventMap.computeIfAbsent(event, k -> new ArrayList<>(16));
		listeners.add(listener);
	}
	
	@SuppressWarnings("all")
	public void callListener(ApplicationEvent event) {
		Class<? extends ApplicationEvent> clazz = event.getClass();
		List<EventListener> listeners = eventMap.get(clazz);
		if (listeners == null || listeners.isEmpty()) {
			return;
		}
		// 丢给线程池跑
		for (EventListener listener : listeners) {
			listenerExecutor.submit(() -> listener.onMessage(event));
		}
	}
	
	
	@Override
	public void removeBeanDefinition(String beanName) {
		beanDefinitionMap.remove(beanName);
		beanNames.remove(beanName);
	}
	
	@Override
	public BeanDefinition getBeanDefinition(String beanName) {
		return beanDefinitionMap.get(beanName);
	}
	
	@Override
	public boolean containsBeanDefinition(String beanName) {
		return beanDefinitionMap.containsKey(beanName);
	}
	
	@Override
	public String[] getBeanDefinitionNames() {
		return beanNames.toArray(new String[0]);
	}
	
	@Override
	public Collection<BeanDefinition> getAllBeanDefinition() {
		return beanDefinitionMap.values();
	}
	
	public Object getBeanByType(Class<?> fieldClass) {
		// 可能存在多个子类 bean
		List<String> beanNames = getAllBeanNameByType(fieldClass);
		
		// 没有相关的bean 定义
		if (beanNames.isEmpty()) {
			throw new RuntimeException("未能找到该类型 [" + fieldClass.getName() + "] 的bean");
		}
		// 可以找到1个,则直接用这个
		if (beanNames.size() == 1) {
			String beanName = beanNames.get(0);
			return getBean(beanName);
		}
		
		// 存在多个符合该类型的bean时，检查有无符合bean名字的
		String beanName = StringUtils.toLowerFirstCase(fieldClass.getSimpleName());
		if (!beanNames.contains(beanName)) {
			throw new RuntimeException("[" + beanName + "] bean 存在多个子类，无法确认选择");
		}
		return getBean(beanName);
	}
	
	
	// 查找某个类及其子类的 所有 bean 信息
	// 用来支持 autowired 注入容器类型数据用
	public List<String> getAllBeanNameByType(Class<?> parentClass) {
		return beanDefinitionMap.values()
				.stream()
				.filter(bd -> parentClass.isAssignableFrom(bd.getBeanClass()))
				.map(BeanDefinition::getBeanName)
				.collect(Collectors.toList());
	}
}
